package states.gameplay;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import states.gameplay.shapors.EnemyCreep;
import states.gameplay.shapors.EnemyCreepGenerator;
import states.gameplay.shapors.Shapor;

public class ShaporGrid {
	//FIXME : Change this to the game and make the constructor receive the sizes
	public static int GRID_WIDTH  = 51;
	public static int GRID_HEIGHT = 37;
	
	public static List<Position> radius_1 = new ArrayList<Position>();
	{
		for(int x = -1; x <= 1; x++){
			for(int y = -1; y <= 1; y++){
				radius_1.add(new Position(x, y));
			}
		}
	}
	
	public static List<Position> radius_2 = new ArrayList<Position>();
	{
		for(int x = -2; x <= 2; x++){
			for(int y = -2; y <= 2; y++){
				radius_2.add(new Position(x, y));
			}
		}
	}
	
	public static List<Position> radius_3 = new ArrayList<Position>();
	{
		for(int x = -3; x <= 3; x++){
			for(int y = -3; y <= 3; y++){
				radius_3.add(new Position(x, y));
			}
		}
		
		// remove corners
		radius_3.remove(new Position(-3, -3));
		radius_3.remove(new Position(-3, 3));
		radius_3.remove(new Position( 3, -3));
		radius_3.remove(new Position(3, 3));
	}
	
	public static List<Position> radius_4 = new ArrayList<Position>();
	{
		for(int x = -4; x <= 4; x++){
			for(int y = -4; y <= 4; y++){
				radius_4.add(new Position(x, y));
			}
		}
		
		// remove corners
		radius_4.remove(new Position(-4, -4));
		radius_4.remove(new Position(-3, -4));
		radius_4.remove(new Position(-4, -3));
		
		radius_4.remove(new Position( 3, -4));
		radius_4.remove(new Position( 4, -4));
		radius_4.remove(new Position( -3, 4));
		
		radius_4.remove(new Position(-4, 3));
		radius_4.remove(new Position(-4, 4));
		radius_4.remove(new Position(-3, 4));
		
		radius_4.remove(new Position(3, 4));
		radius_4.remove(new Position(4, 3));
		radius_4.remove(new Position(4, 4));
	}
	
	public static List<Position> radius_5 = new ArrayList<Position>();
	{
		for(int x = -5; x <= 5; x++){
			for(int y = -5; y <= 5; y++){
				radius_5.add(new Position(x, y));
			}
		}
		
		// remove corners
		radius_5.remove(new Position(-5,-5));
		radius_5.remove(new Position(-5,-4));
		radius_5.remove(new Position(-5,-3));
		radius_5.remove(new Position(-4,-5));
		radius_5.remove(new Position(-4,-4));
		radius_5.remove(new Position(-3,-5));
		
		radius_5.remove(new Position(3,-5));
		radius_5.remove(new Position(4,-5));
		radius_5.remove(new Position(5,-5));
		radius_5.remove(new Position(4,-4));
		radius_5.remove(new Position(5,-4));
		radius_5.remove(new Position(5,-3));
		
		radius_5.remove(new Position(-5,3));
		radius_5.remove(new Position(-5,4));
		radius_5.remove(new Position(-5,5));
		radius_5.remove(new Position(-4,4));
		radius_5.remove(new Position(-4,5));
		radius_5.remove(new Position(-3,5));
		
		radius_5.remove(new Position(3,5));
		radius_5.remove(new Position(4,5));
		radius_5.remove(new Position(5,5));
		radius_5.remove(new Position(4,4));
		radius_5.remove(new Position(5,4));
		radius_5.remove(new Position(5,3));
	}
	
	public Shapor[][] _grid;
	
	private Map<Shapor, Position> _positions;
	private Map<Shapor, List<ShaporLink>> _shaporLinks;
	private List<ShaporLink> _links;
	
	
	public ShaporGrid(){
		_grid = new Shapor[GRID_WIDTH][GRID_HEIGHT];
		
		_positions = new HashMap<Shapor, Position>();
		
		_links = new ArrayList<ShaporLink>();
		
		_shaporLinks = new HashMap<Shapor, List<ShaporLink>>();
	}
	
	public boolean canDeployAt(Shapor shapor, int x, int y){
		boolean result = false;
		
		if ( isInGrid(x, y) ){
			result = true;
		}
		
		return result;
	}
	
	private boolean isInGrid(int x, int y){
		if( (x >= 0 && x < GRID_WIDTH) && (y >= 0 && y < GRID_HEIGHT)){
			return true;
		}
		
		return false;
	}
	
	public void deployShapor(Shapor shapor, int x, int y){
		if(shapor == null){
			throw new IllegalArgumentException("Shapor is null");	
		}
		if( !isInGrid(x, y) ) {
			throw new IllegalArgumentException("X and Y are outside the limits (" + x + "," + y + ")");
		}
		
		_grid[x][y] = shapor;
		_positions.put(shapor, new Position(x, y));
	}
	
	public Position getPositionFor(Shapor shapor){
		return _positions.get(shapor);
	}
	
	public void addLink(Shapor shapor1, Shapor shapor2) {
		ShaporLink link = new ShaporLink();
		link.pos1 = _positions.get(shapor1);
		link.shapor1 = shapor1;
		link.pos2 = _positions.get(shapor2);
		link.shapor2 = shapor2;
		
		_links.add(link);
		
		addLinkToShapor(shapor1, link);
		addLinkToShapor(shapor2, link);
	}
	
	private void addLinkToShapor(Shapor shapor, ShaporLink link) {
		List<ShaporLink> shaporLinks = _shaporLinks.get(shapor);
		
		if(shaporLinks == null){
			shaporLinks = new ArrayList<ShaporGrid.ShaporLink>();
			_shaporLinks.put(shapor, shaporLinks);
		}
		
		shaporLinks.add(link);
	}

	public List<ShaporLink> getAllLinks(){
		return _links;
	}
	
	//>FIXME: Quick radius for time sake, remove the corners on radius > 1
	public boolean isInRadius(Position deployed, Position toDeploy, int radius){
		return getRadiusPositions(deployed, radius).contains(toDeploy);
	}

	public List<Shapor> getAllShapors() {
		List<Shapor> allShapors = new ArrayList<Shapor>();
		allShapors.addAll(_positions.keySet());
		
		return allShapors;
	}
	
	public List<Shapor> getRadiusShapors(Position pos, int radius) {
		
		List<Position> radiusPositions = getRadiusPositions(pos, radius);
	
		List<Shapor> result = new ArrayList<Shapor>();
		
		for(Position rPos : radiusPositions){
			if(_grid[rPos.x][rPos.y] != null){
				result.add(_grid[rPos.x][rPos.y] );
			}
		}
		
//		
//		List<Shapor> result = new ArrayList<Shapor>();
//		
//		int minX = (pos.x - radius) < 0 ? 0 : pos.x - radius;
//		int minY = (pos.y - radius) < 0 ? 0 : pos.y - radius;
//		
//		int maxX = (pos.x + radius) >= ShaporGrid.GRID_WIDTH ? ShaporGrid.GRID_WIDTH - 1: pos.x + radius;
//		int maxY = (pos.y + radius) >= ShaporGrid.GRID_HEIGHT ? ShaporGrid.GRID_HEIGHT - 1: pos.y + radius;
//		
//		for(int x = minX; x <= maxX; x++ ){
//			for(int y = minY; y <= maxY; y++ ){
//				if(_grid[x][y] != null){
//					result.add(_grid[x][y] );
//				}
//			}
//		}
//		
		return result;
	}
	
	public List<Position> getRadiusPositions(Position pos, int radius) {
		
		List<Position> result = new ArrayList<Position>();
		
		List<Position> radiusPos = null;
		switch(radius){
		case 1:
			radiusPos = ShaporGrid.radius_1;
			break;
		case 2:
			radiusPos = ShaporGrid.radius_2;
			break;
		case 3:
			radiusPos = ShaporGrid.radius_3;
			break;
		case 4:
			radiusPos = ShaporGrid.radius_4;
			break;
		case 5:
			radiusPos = ShaporGrid.radius_5;
			break;
		}
		
		for(Position rPos : radiusPos){
			int x = pos.x + rPos.x;
			int y = pos.y + rPos.y;
			
			if(x >= 0 && y >= 0 && x < ShaporGrid.GRID_WIDTH && y < ShaporGrid.GRID_HEIGHT){
				result.add(new Position(pos.x + rPos.x, pos.y + rPos.y ));
			}
		}
		
		return result;
	}
	
//	public List<Position> getRadiusPositions(Position pos, int radius) {
//		
//		List<Position> result = new ArrayList<Position>();
//		
//		int minX = (pos.x - radius) < 0 ? 0 : pos.x - radius;
//		int minY = (pos.y - radius) < 0 ? 0 : pos.y - radius;
//		
//		int maxX = (pos.x + radius) >= ShaporGrid.GRID_WIDTH ? ShaporGrid.GRID_WIDTH - 1: pos.x + radius;
//		int maxY = (pos.y + radius) >= ShaporGrid.GRID_HEIGHT ? ShaporGrid.GRID_HEIGHT - 1: pos.y + radius;
//		
//		for(int x = minX; x <= maxX; x++ ){
//			for(int y = minY; y <= maxY; y++ ){
//				result.add(new Position(x, y));
//			}
//		}
//		
//		return result;
//	}

	public void removeShapor(Shapor shapor) {
		
		// remove it from the positions
		Position pos = _positions.remove(shapor);
				
		// remove it from the grid
		_grid[pos.x][pos.y] = null;
		
		// remove it from the links
		removeAllLinksFor(shapor);
	}
	

	public void removeShaporAt(Position pos) {
		// remove it from the grid
		Shapor shapor = _grid[pos.x][pos.y];
		
		if(shapor != null){
			removeShapor(shapor);
		}
	}
	
	private void removeAllLinksFor(Shapor shapor) {
		// remove the shapor links
		List<ShaporLink> links = _shaporLinks.remove(shapor);
		
		if(links != null){
			// remove all othere links
			for(ShaporLink link : links){
				Shapor other = shapor == link.shapor1 ? link.shapor2 : link.shapor1;
				
				_shaporLinks.get(other).remove(link);
				
				// remove them from the link list
				_links.remove(link);
			}
		}
	}

	public static class ShaporLink{
		public Position pos1;
		public Position pos2;
		
		public Shapor shapor1;
		public Shapor shapor2;
	}

	public Position getRandomPositionForEnemyRadius(Position pos, int radius) {
		//FIXME : not enought time, be fast
		List<Shapor> allShapors = getRadiusShapors(pos, radius);
		Position resultPos = null;
		if(allShapors.size() > 0){
			List<Shapor> finalShapors = new ArrayList<Shapor>();
			
			for(Shapor shapor : allShapors){
				if( shapor instanceof EnemyCreep || shapor instanceof EnemyCreepGenerator) {
					finalShapors.add(shapor);
				}
			}
			
			
			
			if(finalShapors.size() > 0){
				Random r = new Random();
				
				resultPos = getPositionFor(finalShapors.get(r.nextInt(finalShapors.size())));
			}
		}
		
		return resultPos;
	}

}
